import socket
import sys
import threading
import time

def serial_int(n, bcount):
    '''
    serial_int(n, bcount) -> bytearray

    Serialize an integer 'n' to network byte order in 'bcount' bytes
    '''
    buf = bytearray()
    for i in range(bcount - 1, -1, -1):
        buf.append((n & (0xff << (8 * i))) >> (8 * i))
    return buf

def deserial_int(buf):
    '''
    deserial_int(buf) -> integer

    Deserialize a bytearray from network byte order to an integer
    '''
    n = 0
    for i in range(0, len(buf)):
        n <<= 8
        n |= buf[i]
    return n

def sockRecvFully(sock, length):
    '''
    sockRecvFully(sock, length) -> bytearray

    Receive 'length' bytes from 'sock'
    '''
    buf = bytearray()
    while len(buf) < length:
        remains = length - len(buf)
        tmp = sock.recv(remains)
        if tmp == '':
            raise EOFError()
        buf += tmp
    return buf

class RedefFilter(threading.Thread):
    '''
    RedefFilter(sock) -> RedefFilter object

    Define a python source filter setter thread
    '''

    def __init__(self, sock):
        threading.Thread.__init__(self)
        self.filterSource = None
        self.sock = sock

    def run(self):
        '''
        Read the filter python source from file 'filter.py'
        and set to the server every 30 seconds.
        You can modify 'filter.py' when running and the
        new source in 'filter.py' will be apply to server
        within 30 seconds.
        '''
        while True:
            newSource = open('filter.py', 'r').read()
            if newSource == self.filterSource:
                time.sleep(30)
                continue
            srcLenSerial = serial_int(len(newSource), 4)    # serialize the source length
            self.sock.send(srcLenSerial)    # send the source length
            self.sock.send(newSource)   # send the filter source
            print 'set new filter done'
            self.filterSource = newSource
            time.sleep(30)

sock = socket.socket()

if len(sys.argv) < 3:
    print 'Usage: python %s <dest host> <dest port>' % (sys.argv[0], )
    sys.exit(1)

sock.connect((sys.argv[1], int(sys.argv[2])))

RedefFilter(sock).start()

while True: # read packets from server
    packetLen = deserial_int(sockRecvFully(sock, 4))    # receive packet length
    packet = sockRecvFully(sock, packetLen) # receive packet data
    if packet[14] != 8 or packet[15] != 0:  # Is IP protocol?
        print 'Not IP protocol'
        continue
    if packet[16] / 0x10 != 4:  # Is IPv4 protocol?
        print 'Not IPv4 protocol'
        continue
    headLen = packet[16] % 0x10 * 4 # IP head length
    if packet[25] == 6: # Is TCP?
        protocol = 'TCP'
    elif packet[25] == 17:  # Is UDP?
        protocol = 'UDP'
    else:
        print 'Neither TCP nor UDP'
        continue
    srcIP = ''
    for i in range(28, 32): # build readable source IP
        srcIP += str(packet[i])
        srcIP += '.'
    srcIP = srcIP[ : len(srcIP) - 1]
    destIP = ''
    for i in range(32, 36): # build readable destination IP
        destIP += str(packet[i])
        destIP += '.'
    destIP = destIP[ : len(destIP) - 1]
    srcPort = deserial_int(packet[16 + headLen : 18 + headLen]) # build source port
    destPort = deserial_int(packet[18 + headLen : 20 + headLen])    # build destination port
    print protocol + ' transfer from ' + srcIP + ':' + str(srcPort) + ' to ' + destIP + ':' + str(destPort)
